{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "23cba571",
   "metadata": {},
   "source": [
    "# LSTM模型"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d69ca3bf",
   "metadata": {},
   "source": [
    "## 1. 导入必要的库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b43fb71c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "使用设备: cuda\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from torch.utils.data import TensorDataset, DataLoader\n",
    "from sklearn.metrics import mean_squared_error, mean_absolute_error\n",
    "import matplotlib.pyplot as plt\n",
    "import warnings\n",
    "import os\n",
    "import time\n",
    "from datetime import datetime\n",
    "import config\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "plt.rcParams[\"font.sans-serif\"] = [\"SimHei\"]\n",
    "plt.rcParams[\"axes.unicode_minus\"] = False\n",
    "\n",
    "# 创建必要的目录\n",
    "os.makedirs(config.MODEL_DIR, exist_ok=True)\n",
    "os.makedirs(config.OUTPUT_DIR, exist_ok=True)\n",
    "\n",
    "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "print(f\"使用设备: {device}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db76ab1f",
   "metadata": {},
   "source": [
    "## 2. 数据处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8a5ed9df",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在加载训练数据...\n",
      "数据处理完成，形状: (635729, 14)\n",
      "列名: ['StockCode', 'Date', 'Open', 'Close', 'High', 'Low', 'Volume', 'Turnover', 'Amplitude', 'PriceChange', 'TurnoverRate', 'year', 'month', 'day']\n",
      "训练数据股票数量: 300\n",
      "训练数据时间范围: 1 到 2432\n"
     ]
    }
   ],
   "source": [
    "def load_and_process_data(file_path, is_train=True):\n",
    "    \"\"\"加载和处理数据\"\"\"\n",
    "    # 读取数据\n",
    "    data = pd.read_csv(file_path, encoding=\"utf-8\")\n",
    "\n",
    "    # 列名映射\n",
    "    column_mapping = {\n",
    "        \"股票代码\": \"StockCode\",\n",
    "        \"日期\": \"Date\",\n",
    "        \"开盘\": \"Open\",\n",
    "        \"收盘\": \"Close\",\n",
    "        \"最高\": \"High\",\n",
    "        \"最低\": \"Low\",\n",
    "        \"成交量\": \"Volume\",\n",
    "        \"成交额\": \"Turnover\",\n",
    "        \"振幅\": \"Amplitude\",\n",
    "        \"涨跌额\": \"PriceChange\",\n",
    "        \"换手率\": \"TurnoverRate\",\n",
    "        \"涨跌幅\": \"PriceChangePercentage\",\n",
    "    }\n",
    "\n",
    "    # 转换列名\n",
    "    data.rename(columns=column_mapping, inplace=True)\n",
    "\n",
    "    # 删除涨跌幅列（避免数据泄露）\n",
    "    if \"PriceChangePercentage\" in data.columns:\n",
    "        data.drop(columns=[\"PriceChangePercentage\"], inplace=True)\n",
    "\n",
    "    # 日期处理：提取年月日特征\n",
    "    data[\"year\"] = data[\"Date\"].apply(lambda x: int(x.split(\"-\")[0]))\n",
    "    data[\"month\"] = data[\"Date\"].apply(lambda x: int(x.split(\"-\")[1]))\n",
    "    data[\"day\"] = data[\"Date\"].apply(lambda x: int(x.split(\"-\")[2][:2]))\n",
    "\n",
    "    # 将日期转换为序号\n",
    "    unique_dates = pd.Series(data[\"Date\"].unique()).sort_values().reset_index(drop=True)\n",
    "    date_mapping = {date: rank + 1 for rank, date in enumerate(unique_dates)}\n",
    "    data[\"Date\"] = data[\"Date\"].map(date_mapping)\n",
    "\n",
    "    print(f\"数据处理完成，形状: {data.shape}\")\n",
    "    print(f\"列名: {data.columns.tolist()}\")\n",
    "\n",
    "    return data\n",
    "\n",
    "\n",
    "# 加载训练数据\n",
    "print(\"正在加载训练数据...\")\n",
    "train_data_df = load_and_process_data(config.TRAIN_DATA_PATH)\n",
    "print(f\"训练数据股票数量: {train_data_df['StockCode'].nunique()}\")\n",
    "print(\n",
    "    f\"训练数据时间范围: {train_data_df['Date'].min()} 到 {train_data_df['Date'].max()}\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f2efecdd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在创建训练序列...\n",
      "有效股票数量: 300\n",
      "生成序列数量: 626129\n",
      "序列形状: (626129, 32, 14), 标签形状: (626129, 14)\n",
      "输入特征维度: 14\n"
     ]
    }
   ],
   "source": [
    "def create_sequences(data, sequence_length=32):\n",
    "    \"\"\"创建时间序列训练数据\"\"\"\n",
    "    sequences = []\n",
    "    labels = []\n",
    "\n",
    "    # 按股票分组处理\n",
    "    stock_codes = data[\"StockCode\"].unique()\n",
    "    valid_stocks = 0\n",
    "\n",
    "    for stock_code in stock_codes:\n",
    "        stock_data = data[data[\"StockCode\"] == stock_code].sort_values(\"Date\")\n",
    "\n",
    "        # 只保留数值列\n",
    "        numeric_data = stock_data.select_dtypes(include=[np.number]).values\n",
    "\n",
    "        if len(numeric_data) >= sequence_length + 1:\n",
    "            for i in range(len(numeric_data) - sequence_length):\n",
    "                seq = numeric_data[i : i + sequence_length]\n",
    "                label = numeric_data[i + sequence_length]\n",
    "                sequences.append(seq)\n",
    "                labels.append(label)\n",
    "            valid_stocks += 1\n",
    "\n",
    "    print(f\"有效股票数量: {valid_stocks}\")\n",
    "    print(f\"生成序列数量: {len(sequences)}\")\n",
    "\n",
    "    return np.array(sequences), np.array(labels)\n",
    "\n",
    "\n",
    "# 创建训练序列\n",
    "print(\"正在创建训练序列...\")\n",
    "X_train, y_train = create_sequences(train_data_df)\n",
    "print(f\"序列形状: {X_train.shape}, 标签形状: {y_train.shape}\")\n",
    "\n",
    "# 获取特征维度\n",
    "input_size = X_train.shape[2]\n",
    "print(f\"输入特征维度: {input_size}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dcf48ee5",
   "metadata": {},
   "source": [
    "## 3. 模型定义"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d37cd87c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LSTM模型定义完成\n"
     ]
    }
   ],
   "source": [
    "class LSTMModel(nn.Module):\n",
    "    \"\"\"Enhanced LSTM model for time series prediction with attention and multi-layer output head\"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self,\n",
    "        input_size,\n",
    "        hidden_size=256,\n",
    "        num_layers=4,\n",
    "        output_size=1,\n",
    "        dropout=0.1,\n",
    "        use_attention=True,\n",
    "    ):\n",
    "        super(LSTMModel, self).__init__()\n",
    "        self.hidden_size = hidden_size\n",
    "        self.num_layers = num_layers\n",
    "        self.use_attention = use_attention\n",
    "\n",
    "        # LSTM layer\n",
    "        self.lstm = nn.LSTM(\n",
    "            input_size,\n",
    "            hidden_size,\n",
    "            num_layers,\n",
    "            batch_first=True,\n",
    "            dropout=dropout if num_layers > 1 else 0,\n",
    "        )\n",
    "\n",
    "        # Attention layer\n",
    "        if use_attention:\n",
    "            self.attention = nn.Linear(hidden_size, 1)\n",
    "            self.attention_softmax = nn.Softmax(dim=1)\n",
    "\n",
    "        # Multi-layer fully connected head\n",
    "        self.fc1 = nn.Linear(hidden_size, hidden_size // 2)\n",
    "        self.bn1 = nn.BatchNorm1d(hidden_size // 2)\n",
    "        self.fc2 = nn.Linear(hidden_size // 2, output_size)\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "        self.relu = nn.ReLU()\n",
    "\n",
    "    def forward(self, x):\n",
    "        # Initialize hidden state\n",
    "        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)\n",
    "        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(x.device)\n",
    "\n",
    "        # LSTM forward pass\n",
    "        out, _ = self.lstm(x, (h0, c0))\n",
    "\n",
    "        if self.use_attention:\n",
    "            # Apply attention to all time steps\n",
    "            attention_weights = self.attention_softmax(self.attention(out))\n",
    "            out = torch.sum(out * attention_weights, dim=1)\n",
    "        else:\n",
    "            # Use last time step\n",
    "            out = out[:, -1, :]\n",
    "\n",
    "        # Multi-layer output head\n",
    "        out = self.fc1(out)\n",
    "        out = self.bn1(out)\n",
    "        out = self.relu(out)\n",
    "        out = self.dropout(out)\n",
    "        out = self.fc2(out)\n",
    "\n",
    "        return out\n",
    "\n",
    "\n",
    "print(\"LSTM模型定义完成\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd020c1f",
   "metadata": {},
   "source": [
    "## 4. 模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ffb05407",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数值列名: ['StockCode', 'Date', 'Open', 'Close', 'High', 'Low', 'Volume', 'Turnover', 'Amplitude', 'PriceChange', 'TurnoverRate', 'year', 'month', 'day']\n",
      "Close列索引: 3\n",
      "\n",
      "开始训练模型...\n",
      "开始训练，训练样本: 500903, 验证样本: 125226\n",
      "Epoch [5/10], Train Loss: 7768.5403, Val Loss: 138794.8432, Time: 361.71s\n",
      "Epoch [10/10], Train Loss: 7768.7954, Val Loss: 7851.5805, Time: 605.76s\n",
      "训练完成，最佳验证损失: 7708.164965\n"
     ]
    }
   ],
   "source": [
    "def train_model(\n",
    "    X_train,\n",
    "    y_train,\n",
    "    target_column_index,\n",
    "    num_epochs=50,\n",
    "    batch_size=128,\n",
    "    learning_rate=0.001,\n",
    "):\n",
    "    \"\"\"训练模型\"\"\"\n",
    "\n",
    "    # 提取目标列（收盘价）\n",
    "    y_target = y_train[:, target_column_index]  # Close列的索引\n",
    "\n",
    "    # 转换为张量\n",
    "    X_tensor = torch.FloatTensor(X_train).to(device)\n",
    "    y_tensor = torch.FloatTensor(y_target).to(device)\n",
    "\n",
    "    # 划分训练集和验证集\n",
    "    n_samples = len(X_tensor)\n",
    "    n_train = int(n_samples * 0.8)\n",
    "\n",
    "    # 随机打乱数据\n",
    "    indices = torch.randperm(n_samples)\n",
    "    train_indices = indices[:n_train]\n",
    "    val_indices = indices[n_train:]\n",
    "\n",
    "    X_train_split = X_tensor[train_indices]\n",
    "    y_train_split = y_tensor[train_indices]\n",
    "    X_val = X_tensor[val_indices]\n",
    "    y_val = y_tensor[val_indices]\n",
    "\n",
    "    # 创建数据加载器\n",
    "    train_dataset = TensorDataset(X_train_split, y_train_split)\n",
    "    val_dataset = TensorDataset(X_val, y_val)\n",
    "    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
    "    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n",
    "\n",
    "    # 初始化模型\n",
    "    model = LSTMModel(input_size).to(device)\n",
    "    criterion = nn.MSELoss()\n",
    "    optimizer = optim.Adam(model.parameters(), lr=learning_rate)\n",
    "\n",
    "    # 训练历史\n",
    "    train_losses = []\n",
    "    val_losses = []\n",
    "    best_val_loss = float(\"inf\")\n",
    "    best_model_state = None\n",
    "\n",
    "    print(f\"开始训练，训练样本: {len(X_train_split)}, 验证样本: {len(X_val)}\")\n",
    "\n",
    "    start_time = time.time()\n",
    "    for epoch in range(num_epochs):\n",
    "        # 训练阶段\n",
    "        model.train()\n",
    "        train_loss = 0.0\n",
    "        for batch_X, batch_y in train_loader:\n",
    "            optimizer.zero_grad()\n",
    "            outputs = model(batch_X)\n",
    "            loss = criterion(outputs.squeeze(), batch_y)\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "            train_loss += loss.item()\n",
    "\n",
    "        # 验证阶段\n",
    "        model.eval()\n",
    "        val_loss = 0.0\n",
    "        with torch.no_grad():\n",
    "            for batch_X, batch_y in val_loader:\n",
    "                outputs = model(batch_X)\n",
    "                loss = criterion(outputs.squeeze(), batch_y)\n",
    "                val_loss += loss.item()\n",
    "\n",
    "        # 计算平均损失\n",
    "        avg_train_loss = train_loss / len(train_loader)\n",
    "        avg_val_loss = val_loss / len(val_loader)\n",
    "\n",
    "        train_losses.append(avg_train_loss)\n",
    "        val_losses.append(avg_val_loss)\n",
    "\n",
    "        # 保存最佳模型\n",
    "        if avg_val_loss < best_val_loss:\n",
    "            best_val_loss = avg_val_loss\n",
    "            best_model_state = model.state_dict().copy()\n",
    "\n",
    "        if (epoch + 1) % 5 == 0:\n",
    "            elapsed_time = time.time() - start_time\n",
    "            print(\n",
    "                f\"Epoch [{epoch + 1}/{num_epochs}], Train Loss: {avg_train_loss:.4f}, \"\n",
    "                f\"Val Loss: {avg_val_loss:.4f}, Time: {elapsed_time:.2f}s\"\n",
    "            )\n",
    "\n",
    "    # 加载最佳模型\n",
    "    if best_model_state is not None:\n",
    "        model.load_state_dict(best_model_state)\n",
    "\n",
    "    print(f\"训练完成，最佳验证损失: {best_val_loss:.6f}\")\n",
    "\n",
    "    return model, train_losses, val_losses, best_val_loss\n",
    "\n",
    "\n",
    "# 找到Close列的索引\n",
    "close_column_index = None\n",
    "sample_data = train_data_df.select_dtypes(include=[np.number])\n",
    "column_names = sample_data.columns.tolist()\n",
    "for i, col in enumerate(column_names):\n",
    "    if \"Close\" in col:\n",
    "        close_column_index = i\n",
    "        break\n",
    "\n",
    "print(f\"数值列名: {column_names}\")\n",
    "print(f\"Close列索引: {close_column_index}\")\n",
    "\n",
    "# 训练模型\n",
    "print(\"\\n开始训练模型...\")\n",
    "model, train_losses, val_losses, best_val_loss = train_model(\n",
    "    X_train, y_train, close_column_index, num_epochs=10\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "652d03e0",
   "metadata": {},
   "source": [
    "## 5. 模型评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "25ff1141",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAHqCAYAAADVi/1VAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAxfZJREFUeJzs3Xd4FFXbx/HvpkNCEiAkoRNCKKEpCAJKVUCpglgQFBVswCuoqFjAR6RYQX0EpSmK2BUrSG8iFnjooYbeUmhJCEk22Xn/GHYlJkCAJLNJfp/ryrWzc2Zn791Bc3LPOfexGYZhICIiIiIiIiIiUog8rA5ARERERERERERKHiWlRERERERERESk0CkpJSIiIiIiIiIihU5JKRERERERERERKXRKSomIiIiIiIiISKFTUkpERERERERERAqdklIiIiIiIiIiIlLolJQSEREREREREZFCp6SUiIiIiIgUK/fffz/z5s3Ltm/37t1MmDABgCNHjvDmm2+SmZmZ45jVq1fzxx9/5PhZsWIF6enp2Y4fPnw47777brZ933zzDX///fdVf4azZ8/muj8tLY333nvvgu2XyzAM0tLScnwXudm+fTs33nhjju82P6xZs4bk5OQreu2GDRuoW7cumzdvztGWlpYGwJ9//sns2bMBSElJcbUvW7aMEydOXPT8mZmZbN++PU8/Bw8ezHPc9913HxMnTszTsQsXLszzeUWKEiWlRMRtqAOZd+7SgRQREXFHS5Ys4fDhw4D5u9nhcHDkyBHef/99ABISEnj66afx8PAgIyPD1Vf46aefGDlyJN27d6d///68+OKL9O/fn1tvvZUXX3yR06dP07VrV5599lkAYmNjOXbsWLb3Xr9+PR06dGDZsmWufUePHmXWrFm59gOmTZuW7VgAh8NB/fr1mTlzZo7jf/vtN4YPH37J5Ie/vz82m+2SPx4eHpQqVYrly5df4lsFX19fVq9eTVZW1iWPvRwLFizg1ltv5a+//rqi1/v6+rJjxw4Mw8i2/3//+x8NGjTg6NGjLF++nMmTJwNwyy238PHHHwNm//PVV1+96PmPHz9OvXr18vTz2GOP5Xi9YRhkZmbm+PHw8GDKlCnZ9p09ezZHkuzMmTMMHjyYwYMH5/iMIkWdklIi4jbUgSxaHUgRERF35evri7e3NwD9+vUjODiYrl27cujQIYKDg2ndujUA5cqVo2zZskyZMgWAJ554glWrVtG8eXMeeeQRFi9ezP3330/jxo1ZtWoVoaGh+Pr64ufnB4CPjw8+Pj7Z3nvcuHEMGzaM7t278/vvvwNmH+aBBx5w9V0GDhzIrl27ALMfs2nTpmznWLp0KYcOHaJNmzYAbNu2jV27drFv3z4+//xz2rRpg4+PD/v27WP37t1s3ryZM2fOZDtHcHAwL7/8Mnv37s3288QTT/DDDz9k27dz505atGiR7fWnTp1i37592X6c/aeUlJQcbVc6ymnTpk307duXr776iptuusm1f8eOHYwdO5Y33niDN9980/WT2022UqVKAeDhkf3P2yZNmtCmTRuef/55vL298fHx4a+//mL79u306dOH+Ph4Dhw4QJ8+fS4ao6+vL2COqjIM44I/AwYMcB17vtdeew1vb+8cPx9//DGxsbHZ9pUuXZry5cu7RniB2T/8/fffWbNmDS+//HLev1yRIsDL6gBERJz+3YFcvHgxhmFw5swZgoODcTgcgNmBtNvtjB07lieeeML107VrV9q1a8fTTz/N2LFjWbx4sStpk5cOpM1mo3v37ixcuJBWrVq5OpC33XYbpUqVYuDAgYwcOZKoqCh++uknbr75Ztq3b+86R24dSC8vL7y9vXN0IJ13wmrWrIm/v7/rHMHBwTz77LPcd9992eJ79913adeuHY0aNXLts9vtVKxYMdtxp06d4tSpU9n2/bsDeb7y5ctTpkyZS14bERGRoiAmJgYPDw/sdjtHjx5ly5YtzJkzh1KlSrFt2zYmTZrEtGnT2Lt3L4MGDWLJkiW5nsdut+foKzh5eHhgs9kAXI//NnbsWE6fPu26seXsgziTJ1999RUPPPAAUVFReHp64unpme31U6ZM4dFHHyUqKopTp07RvXt3jh07hpeXF6dPnyYgIIBrrrkGMG+KZWRksGLFCq6//nrXOby9vSlfvjw1atTIcW4fHx969OhxkW8SJk6cyCuvvJJr2z333JNj37Rp03jooYcues5/S09Pp2/fvrz66qt06tQpW9uZM2fYsWMHPj4+ru/5119/ZcCAAbRr1w4/P78cSSjnSHIvLy+8vLz4+uuviYqKws/Pjz/++INjx46xatUqevbsyeeff46/vz/BwcHUqlXL1X/KzMykdOnSlC5d2nXef7/PxeT2b8LLy4tGjRqxevVq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t99+6zomPT092+iXyMhIEhMTefrpp/ntt9/o0KFDrrGc39c4ePAggYGBl7zRFRwczCeffMLhw4f573//61qw5ciRI/zf//0fjz76KIcOHeLo0aMYhuFaPMVut1OvXr1s50pOTiYoKIiwsDDXqJutW7fi6+tLq1atXNPMvLy88PPzy1bfCODJJ5/k/vvvZ8uWLa5aTX///Td33nkna9asyTG17N91mS7F19cXDw8Pjh8/fsFRQUFBQfz8889cf/31HD16lPnz5wNm6Yd3332Xr776irvuuivX1wYEBPDCCy/g5eXFd999x5tvvsmSJUs4dOgQ9evXp169etx1112MGDECMBeoiYqKyvFvBODkyZMA2T5zmzZtGDFiBPv376d69equuHJz9uzZbFMt09LSiI+Pp2zZstmOu/POO3N9/b8lJiZmK8QuUpQpKSUillMH8h/u3oEUERFxV8ePH+f//u//ePLJJ3nvvfcAsyZl2bJlefDBB13H1a9fn5dffpk+ffpke31mZiaLFi3iP//5D71793btHzBgAGfOnOHDDz90nSckJIQVK1bQoUMH+vXrd8nYtm3blqfakGCOqunbty8vvviiayTOtm3b2LNnD2PGjGHcuHFkZWWRmprKNddcg91up1SpUiQmJrrOkZiYyNmzZ3P8nv/tt9+47rrrstU9On78eK79geDgYL7//nseeOABPv74Y+677z6WLl1KmTJlctRcuhLe3t5ERkayadMmOnbseMHjqlatyp133sk777xDUlISYCaH7rvvPsaNG3fRRE7r1q1JTk7Gbrfj5eXFrbfeimEYpKam8tdff9GoUSMGDRrEunXrWL16NTfeeGOu59mxYwc2my3bqK5mzZoRFRXFlClTeO211y76WU+fPk14eDgZGRkkJibSrVs3V6Lr386cOXPRGqQOh4OtW7dSt27di76nSFGh6XsiYilnB/L8FeC++uorHnzwQWJiYjhz5gynTp2icuXKzJgxg1OnTpGSksJff/0FXLwD2apVq2xL7VrZgbzmmmu45557XB3Ixo0b56ihkF8dyJUrV9KzZ09WrlxJjRo1SE5OdnUga9Soke2nTJkyefp8IiIi7i4hIQEfHx8GDRrk2le2bFnOnj1LZmama9+JEyeyjVpx1vApX748f//9Nw8//DD79u3jyJEjHDt2jKCgIE6dOsXcuXM5duyY62fu3Lm8/fbblCtX7oIx7dq1C4C1a9fSvHnzS34GwzC444472LRpE3/99RfNmzenTJkyXHvttcTHx3Py5ElOnTrFsmXL8Pf3d039Oj8hBbgWijl/BFJWVhaff/45t9xyS7ZjnbWZcuOsxfTwww8zb948fvzxR5o0aXLJz5FXXbt2ZcaMGRc9Zt++fUydOpWePXsyePBg4uLiAHjooYdo06aNa9Xk3CQkJHDgwAFKlSrF2rVrSUlJYfLkydSsWZNmzZrh6+tLnz59mDhxIt98880Fk2N///0311xzTY7R888++yzvvPMO27Ztu+hnOHr0KBUrVmTz5s3UqFGDypUrU6FChWx9sipVqlC2bFm++OKLi57r559/BrishXxE3JlGSomIpc7vQDrvajo7kN7e3q56Srl1INPT010dyNTUVPbt24ePjw8eHh7ZOpBdunRxvW7u3Ll4eHhcsgMZFRV1RR3IyMhIPvroI2JiYjhw4IBraLaXlxdr166lXbt2nDp1CrvdnmME2MU6kOd3sOHSHchVq1bx8MMPExISku8dSBEREXdUt25d1qxZk2MUcffu3fn777/x9vYmMzMTX19fhg4dyrFjx/D29sbX15e77rqLt956i6CgILp27crq1aux2WyuEdTOulNVqlQBzN/9DoeDzp078+uvv+Yaz/79+2nWrBmLFy/mxx9/5PPPP3e1Xaimo81mIzw8nJYtW1KjRg169+5NdHQ0ZcuW5fTp0zRp0oSpU6e6+hDbtm2ja9eurFy50hUbmEkwT09Patas6do3bdo0jh49yoABA7K957Fjx1yFwnMzdepUjh8/Tq9evVy1lPLL0KFDadiwIatWrcq14HlWVhb33nsv3bt354svvqBFixY8+uijzJ07l6ZNm+YpMTNhwgR8fX2ZP38+ycnJjBs3jpEjR7ran3jiCRo1akR4eDi9evXK8frMzEy+//5710qO53vggQf48MMP6dKlC8uWLbvgang7duzg5ptvpmnTpmRkZLBlyxZat27NqlWraNCgAYZh0L17d4Bso/r+LTU1leeff54nnnhCi9VIsaF/ySJiqYt1IMuXL09ISAjBwcE4HA6GDh1KcHCw687S6NGjAbPewB133EFERARVqlRx/cyePZtffvnF9bxy5cpUqVKFBx544ILxODuQa9eu5ccff+TWW291teW1Azlq1Cg2btxI2bJl8fb2pkmTJqxZs8Z1/LZt26hTpw6HDh3Kdp787kDecsst9OrVi3nz5mUbRSYiIlJcVahQIce+xYsXc/r0aQ4fPkznzp2ZNGkSH3/8Mddccw1btmzh0KFDvPXWW67jFyxYQHp6Og6Hg8zMTDIzMxk8eDB33nmn63lWVhbp6enMnTs31zjOnj3LzJkzueuuu1izZg1BQUHZ+hTn1710Fsl2mjp1KvPnz2fUqFGUL1+emTNncuDAAQYOHEh6ejpRUVGuY+vUqUPFihXp379/tn7KokWLaNy4sasY+vr16xkxYgRPPPGEqz6l0969ey86nd/Ly4uHHnoIh8OB3W5n1qxZLFq0KE+rE19KZGQkzz//PH379uXAgQPZ2pwr0h0+fJipU6fi4eHBlClT+OGHH1i5cmWe3+OVV17h448/5vDhw7Rt25bdu3ezevVq183AtLQ0fH198ff358SJEzle//XXX5OYmJhjuieYZR++/PJL7HY7TZs2zZZ4dDp+/DhbtmyhWbNmrn0NGjTg2WefpWfPnuzfv5+nn36aXbt28cknn1ywbERWVhYPP/wwPj4+F6xdJVIkGSIibiIyMtL46KOPsu1LS0sz7rzzTmPOnDnGH3/8YbRt29Y4duxYjtempKQY6enp2fYNGTLEuOuuu7LtS09PN1JTU3N9/+bNmxs2m814+OGHjXfffdeoWLGikZGR4Wr38/MzVq1aZRiGYfTo0cN49913c5wjKyvLWL16tfHcc88Z+/btM3r37m3Url3bSEhIMP7++2/D39/fyMrKMlq1amW0bdvWyMrKcr22a9euRpMmTVzP//e//xmlS5c2nn322Rzv06pVK6Nbt265fg6nn3/+2fDy8jIA49prrzUWLlxoOByOi75GRESkOIiIiDA+/PBDwzAMY9++fcbkyZONhg0bGpMnT3Yd88UXXxgVK1Y03nzzTePYsWNGYmKisX79eiMmJsbYtm1btp9+/foZXbp0ybF/69atxtq1a7P1TU6dOmUEBAQY1157rRETE2MEBAQYb775Zrb4Xn31VePgwYOGYRjGLbfc4mpPTEw03nvvPeOOO+4wypcvb4SEhBj9+/c3HnjgAaNixYrG3r17DcMwjNWrVxsBAQGGYRjGzp07DV9fX+Odd95xfV5PT0/jpZdeMgzDMObOnWsEBgYa1113XbZ+zeTJk42nnnrK8PLyMoYPH54tPrvdbmzevNl45513jObNmxteXl7GyJEjjZiYGKNv376Gp6enUb58eeOWW24xnnvuOeONN94w3n77beO9997L9h554XA4jPvuu8+oVKmSERMTYxiGYWRmZhq9evUyQkJCjO3bt2c7/tdff81xjsWLFxuAsXPnzlzfY8+ePUb37t2NBg0aGL/++qtx//33G1988YUxY8YMIyAgwBg/frzRqFEjo06dOsaePXtcrzt79qwRFRVltGrV6qKfYceOHUb16tUNwGjYsKHx2muvGYcPHzYMwzA+/PBDo2zZstn6fE533nmn4e/vbwQHBxuxsbEXPL/dbjduu+02IyIiwjhw4MBFYxEpapSUEhG3oQ5k0elAioiIuLNKlSoZU6ZMMXbs2GEEBgYaXbt2NbZs2ZLjuNWrVxuNGjUyunfvbnzxxRdGqVKljMDAQCMoKChPP4GBgYaPj4/xwQcfuM6ZlJRktG/f3ti+fbuxZs0ao1evXhf9PduhQwdj/PjxhmEYxsGDBw0vLy+jV69exsKFC43MzExj8eLFRlBQkLFx40YjPT3dGDx4sHHdddcZdevWdZ1jxIgRRt++fQ3DMIx+/foZnp6exq5du4x169YZISEhxjXXXGPExcVle9+nn37aAIzGjRsbO3bscO3PzMw0OnXqZABGcHCw8fDDD+dIDB0+fNiYPn26cf/99xsNGzY0ypYta3h7e+d6Iy0vsrKyjNdee82Ij4937fvxxx+NjRs3XvR1SUlJRmBgoAEY9erVM+x2e7b2OXPmGF27djUCAgKMZ5991nVj8n//+59x4403GsHBwcaXX37p+kz169c3AgICjGXLlhmGYRiDBw82AGPx4sWX/AwJCQlG7969DcCoUaOGkZKSYhiGYTRs2NB47LHHjKysLCMxMdH4/fffjYkTJxodOnQw/P39je7duxsVKlQwwsLCjDvvvNMYP368MWfOnBzJtzfeeMM4evToJeMQKWqUlBIRt6EOZNHqQIqIiBQFSUlJF213OBzGmTNnCimaSzs/MeN0/uidp59+2njkkUeMtWvXuvadn4w5fvy48fXXX2d77cmTJ3Oc88SJE8aJEydyjeHAgQPGqlWrciR53NF3331nrFq1KseIecMwjEWLFhnjxo3L0Z9KSkoynn322Ryj71NTU43333/f9Xznzp3Giy++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OZnY2NgLvq+HhwdnzpxhwoQJTJkyJddjVqxYQePGjbHb7Tz44IOMHDmSl156CTCHvnt7e3PkyJFcf79f6D1tNluu/27171hE3F5KPDZH/hVeFils7tI3upQVK1bk2je6WOHzb7/9lvXr17Nx40YmTpxI165defTRR119o/79+1+ybwRmXiOvfaP777//qvtG+cFtklKfffYZCQkJBAcHA+Yw+K+++oq//vqLZs2a8dlnn7mOXb9+PZUrVwagWbNmrFmzhoEDB16w7aabbsrRdt1117FmzRoiIyNdbecXVxeRIuzoRrymtadFQF1wdAH0x6IUPWftWUSPXnDpAwtAzJjO+HnlbS2Ubt260a1bN/7zn/9w5swZ1/6zZ8/mehcQICgoiNatW7Nv3z6WLFnCjh07CA8PZ+DAgbRr14477riDsLCwXF976NAhjh8/zrBhw2jXrh3BwcEMHz6c//znPxw9epTy5cvj4+NDjRo1XDebzpw5Q//+/bPd5Ttx4gTe3t45Ol1ZWWZn9981o0REirQd8/H6oh83ewXhUekENB0AXhe+IS/ijtQ3Kp59I0tW38vNqlWr2LJlCxs2bGDDhg306NGDMWPGMGbMGHr06MHq1atZvHgxdrud119/nc6dOwNw++2388UXX7B582ZSUlJ49913XW19+vRhypQpHD58mLi4OGbOnJmt7bXXXiMpKYmdO3fyzTffuNpEpIjb8h02I4vQ5K14rMlZ0E9ECsb5nZX4+Pgcw8Sdbr75ZqZPn05cXByvvPIK4eHhbN++nQULFnDHHXcAuIaN2+12153FoUOHEhUVxb59+xgyZAhTp07NNrXwrrvuck3NO/8c3377LcOHDyc0NJSQkBBCQkKoVasWdrudwMBA177y5cvj7+/Pp59+mr9fjIiIldKT4ecnsRlZlLafwHP+CPhvU1g3C7K0SINIQVLf6NLcZqRUlSpVsj0PCAhwfREAkyZNokuXLgQEBBAcHMysWbMAaNy4McOGDeO6667Dz8+PqKgoBg8eDED37t35+uuviYqKAuCmm26id+/eADzyyCP88MMPVKlShfT0dAYNGkTTpk0L6dOKSIGKXeLa9FjxKtTqAFWuszAgkctXytuTmDHW3Cwp5e3pWn3vSm3bts01Gjk3P/74I/v372fWrFmkpqby008/kZKSQt26dV3F0GvUqEFaWhqj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",
      "text/plain": [
       "<Figure size 1200x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最终训练损失: 7768.795409\n",
      "最终验证损失: 7851.580509\n",
      "最佳验证损失: 7708.164965\n"
     ]
    }
   ],
   "source": [
    "# 绘制训练历史\n",
    "plt.figure(figsize=(12, 5))\n",
    "\n",
    "plt.subplot(1, 2, 1)\n",
    "plt.plot(train_losses, label=\"训练损失\")\n",
    "plt.plot(val_losses, label=\"验证损失\")\n",
    "plt.title(\"模型训练历史\")\n",
    "plt.xlabel(\"Epoch\")\n",
    "plt.ylabel(\"Loss\")\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.plot(train_losses, label=\"训练损失\")\n",
    "plt.plot(val_losses, label=\"验证损失\")\n",
    "plt.title(\"模型训练历史（对数尺度）\")\n",
    "plt.xlabel(\"Epoch\")\n",
    "plt.ylabel(\"Loss (log scale)\")\n",
    "plt.yscale(\"log\")\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(f\"最终训练损失: {train_losses[-1]:.6f}\")\n",
    "print(f\"最终验证损失: {val_losses[-1]:.6f}\")\n",
    "print(f\"最佳验证损失: {best_val_loss:.6f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "d7ad462d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "模型已保存到: ../../model\\lstm_model.pth\n"
     ]
    }
   ],
   "source": [
    "# 保存模型\n",
    "model_save_path = os.path.join(config.MODEL_DIR, \"lstm_model.pth\")\n",
    "torch.save(\n",
    "    {\n",
    "        \"model_state_dict\": model.state_dict(),\n",
    "        \"best_val_loss\": best_val_loss,\n",
    "        \"input_size\": input_size,\n",
    "        \"close_column_index\": close_column_index,\n",
    "    },\n",
    "    model_save_path,\n",
    ")\n",
    "\n",
    "print(f\"模型已保存到: {model_save_path}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a026210b",
   "metadata": {},
   "source": [
    "## 6. 测试数据处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "eaa0dab0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在加载测试数据...\n",
      "数据处理完成，形状: (637229, 14)\n",
      "列名: ['StockCode', 'Date', 'Open', 'Close', 'High', 'Low', 'Volume', 'Turnover', 'Amplitude', 'PriceChange', 'TurnoverRate', 'year', 'month', 'day']\n",
      "测试数据股票数量: 300\n",
      "测试数据时间范围: 1 到 2437\n"
     ]
    }
   ],
   "source": [
    "# 加载测试数据\n",
    "print(\"正在加载测试数据...\")\n",
    "test_data_df = load_and_process_data(config.TEST_DATA_PATH, is_train=False)\n",
    "\n",
    "# 获取测试数据中的股票代码\n",
    "test_stock_codes = test_data_df[\"StockCode\"].unique()\n",
    "print(f\"测试数据股票数量: {len(test_stock_codes)}\")\n",
    "print(f\"测试数据时间范围: {test_data_df['Date'].min()} 到 {test_data_df['Date'].max()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4cef0fb",
   "metadata": {},
   "source": [
    "## 7. 预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e8c1e547",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始预测...\n",
      "预测完成，耗时: 2.74秒\n",
      "成功预测 300 支股票\n"
     ]
    }
   ],
   "source": [
    "def predict_stock_prices(model, test_data, stock_codes, sequence_length=32):\n",
    "    \"\"\"预测股票价格\"\"\"\n",
    "    model.eval()\n",
    "    predictions = []\n",
    "\n",
    "    max_date = test_data[\"Date\"].max()\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for stock_code in stock_codes:\n",
    "            try:\n",
    "                # 获取该股票的最新32天数据\n",
    "                stock_data = test_data[\n",
    "                    test_data[\"StockCode\"] == stock_code\n",
    "                ].sort_values(\"Date\")\n",
    "\n",
    "                # 取最后32天的数据\n",
    "                if len(stock_data) >= sequence_length:\n",
    "                    recent_data = stock_data.tail(sequence_length)\n",
    "\n",
    "                    # 提取数值特征\n",
    "                    numeric_data = recent_data.select_dtypes(include=[np.number]).values\n",
    "\n",
    "                    # 转换为张量\n",
    "                    sequence = (\n",
    "                        torch.FloatTensor(numeric_data).unsqueeze(0).to(device)\n",
    "                    )  # 添加batch维度\n",
    "\n",
    "                    # 预测\n",
    "                    pred = model(sequence)\n",
    "                    predicted_close = pred.cpu().numpy()[0, 0]  # 提取预测的收盘价\n",
    "\n",
    "                    # 获取当前收盘价\n",
    "                    current_close = stock_data[stock_data[\"Date\"] == max_date][\n",
    "                        \"Close\"\n",
    "                    ].iloc[0]\n",
    "\n",
    "                    # 计算涨跌幅\n",
    "                    change_rate = (\n",
    "                        (predicted_close - current_close) / current_close * 100\n",
    "                    )\n",
    "\n",
    "                    predictions.append(\n",
    "                        (stock_code, predicted_close, current_close, change_rate)\n",
    "                    )\n",
    "\n",
    "            except Exception as e:\n",
    "                print(f\"处理股票 {stock_code} 时出错: {e}\")\n",
    "                continue\n",
    "\n",
    "    return predictions\n",
    "\n",
    "\n",
    "# 进行预测\n",
    "print(\"开始预测...\")\n",
    "start_time = time.time()\n",
    "predictions = predict_stock_prices(model, test_data_df, test_stock_codes)\n",
    "end_time = time.time()\n",
    "\n",
    "print(f\"预测完成，耗时: {end_time - start_time:.2f}秒\")\n",
    "print(f\"成功预测 {len(predictions)} 支股票\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0d78640",
   "metadata": {},
   "source": [
    "## 8. 结果分析和输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4cf4e9d4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "预测结果统计:\n",
      "总股票数: 300\n",
      "预测上涨股票数: 200 (66.7%)\n",
      "预测下跌股票数: 100 (33.3%)\n",
      "最大涨幅: 1617.92%\n",
      "最大跌幅: -98.02%\n",
      "平均涨跌幅: 130.94%\n",
      "\n",
      "涨幅最大的10支股票:\n",
      "1. 600010: 1617.92%\n",
      "2. 601868: 1272.80%\n",
      "3. 601618: 942.40%\n",
      "4. 601916: 921.62%\n",
      "5. 630: 873.12%\n",
      "6. 600219: 786.19%\n",
      "7. 600515: 771.13%\n",
      "8. 3816: 771.13%\n",
      "9. 600115: 726.63%\n",
      "10. 601818: 707.11%\n",
      "\n",
      "跌幅最大的10支股票:\n",
      "1. 300760: -85.83%\n",
      "2. 300750: -87.00%\n",
      "3. 300033: -88.18%\n",
      "4. 688506: -88.89%\n",
      "5. 605499: -88.93%\n",
      "6. 688111: -89.20%\n",
      "7. 2594: -91.71%\n",
      "8. 2371: -93.22%\n",
      "9. 688256: -95.54%\n",
      "10. 600519: -98.02%\n",
      "\n",
      "预测结果已保存到: ../../output/result.csv\n",
      "\n",
      "最终预测结果:\n",
      "   涨幅最大股票代码  涨幅最小股票代码\n",
      "0    600010    300760\n",
      "1    601868    300750\n",
      "2    601618    300033\n",
      "3    601916    688506\n",
      "4       630    605499\n",
      "5    600219    688111\n",
      "6    600515      2594\n",
      "7      3816      2371\n",
      "8    600115    688256\n",
      "9    601818    600519\n",
      "详细预测结果已保存到: ../../output\\detailed_predictions.csv\n"
     ]
    }
   ],
   "source": [
    "if predictions:\n",
    "    # 按涨跌幅排序\n",
    "    predictions_sorted = sorted(predictions, key=lambda x: x[3], reverse=True)\n",
    "\n",
    "    # 提取涨跌幅数据\n",
    "    change_rates = [pred[3] for pred in predictions_sorted]\n",
    "\n",
    "    # 统计信息\n",
    "    max_increase = max(change_rates)\n",
    "    max_decrease = min(change_rates)\n",
    "    mean_change = np.mean(change_rates)\n",
    "    positive_count = sum(1 for rate in change_rates if rate > 0)\n",
    "    negative_count = sum(1 for rate in change_rates if rate < 0)\n",
    "\n",
    "    print(\"\\n预测结果统计:\")\n",
    "    print(f\"总股票数: {len(predictions)}\")\n",
    "    print(\n",
    "        f\"预测上涨股票数: {positive_count} ({positive_count/len(predictions)*100:.1f}%)\"\n",
    "    )\n",
    "    print(\n",
    "        f\"预测下跌股票数: {negative_count} ({negative_count/len(predictions)*100:.1f}%)\"\n",
    "    )\n",
    "    print(f\"最大涨幅: {max_increase:.2f}%\")\n",
    "    print(f\"最大跌幅: {max_decrease:.2f}%\")\n",
    "    print(f\"平均涨跌幅: {mean_change:.2f}%\")\n",
    "\n",
    "    # 获取涨幅最大和最小的前10支股票\n",
    "    top_10_gainers = [pred[0] for pred in predictions_sorted[:10]]\n",
    "    top_10_losers = [pred[0] for pred in predictions_sorted[-10:]]\n",
    "\n",
    "    print(\"\\n涨幅最大的10支股票:\")\n",
    "    for i, pred in enumerate(predictions_sorted[:10]):\n",
    "        print(f\"{i+1}. {pred[0]}: {pred[3]:.2f}%\")\n",
    "\n",
    "    print(\"\\n跌幅最大的10支股票:\")\n",
    "    for i, pred in enumerate(predictions_sorted[-10:]):\n",
    "        print(f\"{i+1}. {pred[0]}: {pred[3]:.2f}%\")\n",
    "\n",
    "    # 创建结果DataFrame\n",
    "    result_data = {\n",
    "        \"涨幅最大股票代码\": top_10_gainers + [\"\"] * (10 - len(top_10_gainers)),\n",
    "        \"涨幅最小股票代码\": top_10_losers + [\"\"] * (10 - len(top_10_losers)),\n",
    "    }\n",
    "\n",
    "    result_df = pd.DataFrame(result_data)\n",
    "\n",
    "    # 保存结果\n",
    "    result_df.to_csv(config.RESULT_PATH, index=False)\n",
    "    print(f\"\\n预测结果已保存到: {config.RESULT_PATH}\")\n",
    "\n",
    "    # 显示结果\n",
    "    print(\"\\n最终预测结果:\")\n",
    "    print(result_df)\n",
    "\n",
    "    # 保存详细预测结果\n",
    "    detailed_results = []\n",
    "    for i, (stock_code, pred_price, current_price, change_rate) in enumerate(\n",
    "        predictions_sorted\n",
    "    ):\n",
    "        detailed_results.append(\n",
    "            {\n",
    "                \"排名\": i + 1,\n",
    "                \"股票代码\": stock_code,\n",
    "                \"当前收盘价\": f\"{current_price:.2f}\",\n",
    "                \"预测收盘价\": f\"{pred_price:.2f}\",\n",
    "                \"预测涨跌幅(%)\": f\"{change_rate:.4f}\",\n",
    "            }\n",
    "        )\n",
    "\n",
    "    detailed_df = pd.DataFrame(detailed_results)\n",
    "    detailed_output_path = os.path.join(config.OUTPUT_DIR, \"detailed_predictions.csv\")\n",
    "    detailed_df.to_csv(detailed_output_path, index=False)\n",
    "    print(f\"详细预测结果已保存到: {detailed_output_path}\")\n",
    "\n",
    "else:\n",
    "    print(\"未能生成有效的预测结果\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f09f912",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
